package com.b2c.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.b2c.pojo.dto.RedisStreamEmailDTO;
import com.b2c.properties.JwtProperties;
import com.b2c.mapper.AdminUserMapper;
import com.b2c.pojo.dto.AdminUserDto;
import com.b2c.pojo.entity.AdminUser;
import com.b2c.pojo.vo.CodeEmailVo;
import com.b2c.pojo.vo.CodePhoneVO;
import com.b2c.pojo.vo.EmailVo;
import com.b2c.pojo.vo.PhoneVo;
import content.enumeration.BindWayType;
import content.enumeration.LoginStatus;
import content.enumeration.RegisterWayEnum;
import util.AdminUserToken;
import result.Result;
import com.b2c.properties.ThreadPoolProperties;
import com.b2c.service.AdminUserService;
import com.b2c.util.SendEmailUtil;
import util.ThreadLocalUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.connection.stream.*;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import util.JwtUtil;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import static content.common.CommonName.*;
import static content.common.RedisCommon.*;
import static content.common.Regexp.ARRAY_TOSTRING_REGEXP;
import static content.common.ResultMessage.*;
import static content.common.TemplateCommon.QqEmailTemplateCommon.EMAIL_CODE;

/**
 * @author Administrator
 * @description 针对表【mall_admin_user】的数据库操作Service实现
 * @createDate 2024-03-13 16:31:13
 */
@Service
@Slf4j
public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser>
        implements AdminUserService {

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private JwtProperties jwtProperties;

    public AdminUserServiceImpl() {
    }
    /**
     * 邮箱登录
     *
     * @param
     * @return
     */
    @Override
    public Result adminLoginEmail(CodeEmailVo codeEmailVo) {
        log.info("邮箱登录:{}", codeEmailVo.getEmail());
        RBucket<String> bucket = redissonClient.getBucket(codeEmailVo.getEmail());
        String redisCode = bucket.get();
        //校验验证码
        if (StrUtil.isBlank(redisCode) || !redisCode.equals(codeEmailVo.getCode())) {
            return Result.fail(CODE_ERROR);
        }
        //校验完后删除
        bucket.delete();
        //从数据库获取用户信息
        AdminUser adminUser = getOne(
                new QueryWrapper<AdminUser>()
                        .eq("email", codeEmailVo.getEmail())
        );
        //判断用户存在
        if (adminUser == null) {
            return Result.fail(ADMIN_USER_NOT_EXIST);
        }
        //判断用户账号状态
        if (!adminUser.getStatus().equals(LoginStatus.logout)) {
            return adminUser.getStatus() == LoginStatus.login ? Result.fail(USER_ALREADY_LOGIN) : Result.fail(USER_AMOUNT_ERROR);
        }
        AdminUserDto adminUserDto = BeanUtil.copyProperties(adminUser, AdminUserDto.class);
        //生成JWT令牌
        HashMap<String, Object> claim = new HashMap<>();
        claim.put(ADMIN_INFO_CLAIMS_NAME, adminUserDto);
        String jwt = JwtUtil.createJwt(jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claim);
        return Result.success(jwt);
    }

    /**
     * 手机号登录
     *
     * @param codePhoneVO
     * @return
     */
    @Override
    public Result adminLoginPhone(CodePhoneVO codePhoneVO) {
        log.info("账号登录:手机号{}，验证码{}", codePhoneVO.getPhone(), codePhoneVO.getCode());
        RBucket<String> bucket = redissonClient.getBucket(codePhoneVO.getPhone());
        //获取存入的验证码
        String redisCode = bucket.get();
        //进行校验
        if (StrUtil.isBlank(redisCode) || !redisCode.equals(codePhoneVO.getCode())) {
            return Result.fail(CODE_ERROR);
        }
        //校验完后删除验证码
        bucket.delete();
        //从数据库中获取用户信息
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", codePhoneVO.getPhone());
        AdminUser adminUser = getOne(queryWrapper);
        if (adminUser == null) {
            return Result.fail(ADMIN_USER_NOT_EXIST);
        }
        AdminUserDto adminUserDto = BeanUtil.copyProperties(adminUser, AdminUserDto.class);
        //生成JWT令牌
        HashMap<String, Object> claim = new HashMap<>();
        claim.put(ADMIN_INFO_CLAIMS_NAME, adminUserDto);
        String jwt = JwtUtil.createJwt(jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claim);
        return Result.success(jwt);
    }


    /**
     * 账号密码登录
     *
     * @param username
     * @param password
     * @return
     */
    @Override
    public Result adminLoginSecret(String username, String password) {
        log.info("账号:{},密码:{}登录", username, password);
        //对密码进行md5加密
        String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes());
        //在数据库中查询
        QueryWrapper<AdminUser> adminUserQueryWrapper = new QueryWrapper<>();
        adminUserQueryWrapper.eq("username", username).eq("password", passwordMd5);
        AdminUser adminUser = getOne(adminUserQueryWrapper);
        if (adminUser == null) {
            //账号或密码不正确
            return Result.fail(USERNAME_OR_PASSWORD_ERROR);
        }
        AdminUserDto adminUserDto = BeanUtil.copyProperties(adminUser, AdminUserDto.class);
        //生成JWT令牌
        HashMap<String, Object> claim = new HashMap<>();
        claim.put(ADMIN_INFO_CLAIMS_NAME, adminUserDto);
        String jwt = JwtUtil.createJwt(jwtProperties.getAdminSecretKey(), jwtProperties.getAdminTtl(), claim);

        //返回jwt令牌
        return Result.success(jwt);
    }

    /**
     * 更改密码
     *
     * @param password
     * @return
     */
    @Override
    public Result updateSecret(String password) {
        //从ThreadLocal中获取用户信息
        AdminUserToken adminUserToken = new ThreadLocalUtil<AdminUserToken>().get();
        log.info("用户:{},修改密码为:{}", adminUserToken.getUsername(), password);
        //更改数据库，修改密码
        UpdateWrapper<AdminUser> adminUserUpdateWrapper = new UpdateWrapper<>();
        adminUserUpdateWrapper.eq("id", adminUserToken.getId()).set("password", password);
        boolean isUpdate = update(adminUserUpdateWrapper);
        if (!isUpdate) {
            return Result.fail(UPDATE_PASSWORD_FAIL);
        }
        return Result.success();
    }


    /**
     * 绑定手机号
     *
     * @param
     * @return
     */
    @Override
    public Result bindPhone(CodePhoneVO codePhoneVO) {
        String phone = codePhoneVO.getPhone();
        String code = codePhoneVO.getCode();
        //获取用户信息
        AdminUserToken adminUserToken = new ThreadLocalUtil<AdminUserToken>().get();
        log.info("用户{}绑定手机号{}，验证码{}", adminUserToken.getUsername(), phone, code);
        //获取redis验证码
        RBucket<String> bucket = redissonClient.getBucket(phone);
        String redisCode = bucket.get();
        //校验验证码
        if (StrUtil.isBlank(redisCode) || redisCode.equals(code)) {
            return Result.fail(CODE_ERROR);
        }
        //绑定到数据库
        String errorMessage = bind(BindWayType.phone, phone, adminUserToken.getId());
        if (errorMessage != null) {
            return Result.fail(errorMessage);
        }

        return Result.success();
    }

    /**
     * 绑定邮箱
     *
     * @param codeEmailVo
     * @return
     */
    @Override
    public Result bindEmail(CodeEmailVo codeEmailVo) {
        String email = codeEmailVo.getEmail();
        String code = codeEmailVo.getCode();
        //获取用户信息
        AdminUserToken adminUserToken = new ThreadLocalUtil<AdminUserToken>().get();
        log.info("用户{}绑定邮箱{}，验证码{}", adminUserToken.getUsername(), email, code);
        RBucket<String> bucket = redissonClient.getBucket(email);
        String redisCode = bucket.get();
        //校验验证码
        if (StrUtil.isBlank(redisCode) || redisCode.equals(code)) {
            return Result.fail(CODE_ERROR);
        }
        //绑定到数据库
        String errorMessage = bind(BindWayType.email, email, adminUserToken.getId());
        if (errorMessage != null) {
            return Result.fail(errorMessage);
        }

        return Result.success();
    }

    /**
     * 登出用户
     *
     * @return
     */
    @Override
    public Result logout() {
        Integer userId = new ThreadLocalUtil<AdminUserToken>().get().getId();
        update(new UpdateWrapper<AdminUser>()
                .set("status", LoginStatus.login)
                .eq("id", userId));

        return Result.success();
    }

    /**
     * 账号绑定
     *
     * @param bindWay
     * @param bindCode
     * @param bindUserId
     * @return
     */
    private String bind(BindWayType bindWay, String bindCode, Integer bindUserId) {
        //绑定前判断当前账号是否被使用过，一个号只能绑定一次
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<AdminUser>().eq(String.valueOf(bindWay), bindCode);
        long count = count(queryWrapper);
        if (count > 0) {
            return ONLY_USE_ONE;
        }
        //更改数据库，绑定手机号
        UpdateWrapper<AdminUser> adminUserUpdateWrapper =
                new UpdateWrapper<AdminUser>()
                        .set(String.valueOf(bindWay), bindCode)
                        .eq("id", bindUserId);
        boolean isUpdate = update(adminUserUpdateWrapper);
        if (!isUpdate) {
            return BIND_PASSWORD_FAIL;
        }
        return null;
    }

    /**
     * 设置密码
     *
     * @param password
     * @return
     */
    @Override
    public Result setupSecret(String password) {
        //获取用户信息
        AdminUserToken adminUserToken = new ThreadLocalUtil<AdminUserToken>().get();
        String username = adminUserToken.getUsername();
        log.info("用户{}，设置密码{}", username, password);
        //更改数据库
        UpdateWrapper<AdminUser> adminUserUpdateWrapper = new UpdateWrapper<>();
        adminUserUpdateWrapper.eq("id", adminUserToken.getId()).set("password", password);
        boolean isUpdate = update(adminUserUpdateWrapper);
        if (isUpdate) {
            return Result.fail(SETUP_PASSWORD_FAIL);
        }
        return Result.success();
    }




    /**
     * 手机号注册
     *
     * @param codePhoneVO
     * @return
     */
    @Override
    public Result registerByPhone(CodePhoneVO codePhoneVO) {
        log.info("手机号注册:{}，验证码：{}", codePhoneVO.getPhone(), codePhoneVO.getCode());
        String phone = codePhoneVO.getPhone();
        String code = codePhoneVO.getCode();
        RBucket<String> bucket = redissonClient.getBucket(phone);
        String redisCode = bucket.get();
        //校验验证码
        if (StrUtil.isBlank(redisCode) || redisCode.equals(code)) {
            return Result.fail(CODE_ERROR);
        }
        AdminUserDto adminUserDto = register(RegisterWayEnum.phone, phone);
        if (adminUserDto == null) {
            bucket.delete();
            return Result.fail(ALREADY_REGISTER);
        }
        bucket.delete();
        return Result.success();
    }

    /**
     * 邮箱注册
     *
     * @param codeEmailVo
     * @return
     */
    @Override
    public Result registerByEmail(CodeEmailVo codeEmailVo) {
        String email = codeEmailVo.getEmail();
        String code = codeEmailVo.getCode();

        log.info("邮箱注册:{},验证码:{}", email, code);
        RBucket<String> bucket = redissonClient.getBucket(email);
        String redisCode = bucket.get();
        if (StrUtil.isBlank(redisCode) || redisCode.equals(code)) {
            return Result.fail(CODE_ERROR);
        }
        //注册到数据库中
        AdminUserDto adminUserDto = register(RegisterWayEnum.email, email);
        if (adminUserDto == null) {
            bucket.delete();
            return Result.fail(ALREADY_REGISTER);
        }
        bucket.delete();
        return Result.success();
    }


    /**
     * 新管理员注册账号到数据库中
     *
     * @param registerWay
     * @param registerCode
     * @return
     */
    private AdminUserDto register(RegisterWayEnum registerWay, String registerCode) {
        //是否注册过
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<AdminUser>().eq(String.valueOf(registerWay), registerCode);
        long registerCount = count(queryWrapper);
        if (registerCount > 0) {
            return null;
        }
        //构造用户信息
        AdminUser adminUser = AdminUser.builder()
                .nickName(NICK_NAME_FREFIX + RandomUtil.randomString(16))
                .username(registerCode).build();
        if (registerWay.equals(RegisterWayEnum.phone)) {
            adminUser.setPhone(registerCode);
        }
        if (registerWay.equals(RegisterWayEnum.email)) {
            adminUser.setEmail(registerCode);
        }
        //保存到数据库
        boolean isSave = save(adminUser);
        if (!isSave) {
            return null;
        }
        return BeanUtil.copyProperties(adminUser, AdminUserDto.class);
    }



}




